package com.ethink.framework.redis.config;

import com.ethink.framework.redis.cache.CacheEntityMap;
import com.ethink.framework.redis.mq.RedisMqListenerRegister;
import com.ethink.framework.redis.mq.RedisMqPublisher;
import com.ethink.framework.redis.properties.CacheManagerProperties;
import com.ethink.framework.redis.properties.RedisMqProperties;
import com.baomidou.mybatisplus.core.toolkit.CollectionUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.autoconfigure.data.redis.RedisProperties;
import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.cache.CacheManager;
import org.springframework.cache.annotation.EnableCaching;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Primary;
import org.springframework.data.redis.cache.RedisCacheConfiguration;
import org.springframework.data.redis.cache.RedisCacheManager;
import org.springframework.data.redis.connection.RedisConnectionFactory;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.data.redis.serializer.GenericJackson2JsonRedisSerializer;
import org.springframework.data.redis.serializer.RedisSerializationContext;
import org.springframework.data.redis.serializer.RedisSerializer;
import org.springframework.data.redis.serializer.StringRedisSerializer;

import java.time.Duration;
import java.util.HashMap;
import java.util.Map;

/**
 * redis 配置类
 *
 * @author yunduo
 * @date 2018/11/6 11:02
 */
@EnableConfigurationProperties({RedisProperties.class, CacheManagerProperties.class, RedisMqProperties.class})
@EnableCaching
@Configuration
public class RedisAutoConfigure {

    @Autowired
    private CacheManagerProperties cacheManagerProperties;


    @Autowired
    private RedisMqProperties redisMqProperties;

    @Bean
    public CacheEntityMap cacheEntityMap(StringRedisTemplate stringRedisTemplate) {
        CacheEntityMap cacheEntityMap = new CacheEntityMap();
        cacheEntityMap.setStringRedisTemplate(stringRedisTemplate);
        cacheEntityMap.setCheckInterval(cacheManagerProperties.getCacheEntityMapCheckInterval());
        cacheEntityMap.setRefreshEnable(cacheManagerProperties.isCacheEntityMapRefreshEnable());
        return cacheEntityMap;
    }


    /**
     * RedisTemplate配置
     *
     * @param factory
     */
    @Bean
    public RedisTemplate<String, Object> redisTemplate(RedisConnectionFactory factory) {
        RedisTemplate<String, Object> redisTemplate = new RedisTemplate<>();
        redisTemplate.setConnectionFactory(factory);
        redisTemplate.setKeySerializer(keySerializer());
        redisTemplate.setValueSerializer(valueSerializer());
        redisTemplate.setHashKeySerializer(keySerializer());
        redisTemplate.setHashValueSerializer(valueSerializer());
        redisTemplate.afterPropertiesSet();
        return redisTemplate;
    }

    @Bean(name = "cacheManager")
    @Primary
    public CacheManager cacheManager(RedisConnectionFactory redisConnectionFactory) {
        RedisSerializer<String> keySerializer = keySerializer();
        RedisSerializer<Object> valueSerializer = valueSerializer();
        RedisCacheConfiguration difConf = getDefConf(keySerializer, valueSerializer).entryTtl(Duration.ofHours(1));
        //自定义的缓存过期时间配置
        Map<String, RedisCacheConfiguration> redisCacheConfigurationMap = new HashMap<>();
        if (CollectionUtils.isNotEmpty(cacheManagerProperties.getConfigs())) {
            cacheManagerProperties.getConfigs().forEach(e -> {
                RedisCacheConfiguration conf = getDefConf(keySerializer, valueSerializer).entryTtl(Duration.ofSeconds(e.getSecond()));
                redisCacheConfigurationMap.put(e.getKey(), conf);
            });
        }
        return RedisCacheManager.builder(redisConnectionFactory)
                .cacheDefaults(difConf)
                .withInitialCacheConfigurations(redisCacheConfigurationMap)
                .build();
    }

    @Bean
    public RedisMqPublisher redisMqPublisher(RedisTemplate redisTemplate) {
        RedisMqPublisher redisMqPublisher = new RedisMqPublisher();
        redisMqPublisher.setRedisTemplate(redisTemplate);
        return redisMqPublisher;
    }

    @Bean
    public RedisMqListenerRegister redisMqListenerRegister(RedisTemplate redisTemplate, RedisMqPublisher redisMqPublisher) {
        RedisMqListenerRegister redisListenerRegister = new RedisMqListenerRegister();
        redisListenerRegister.setPublisher(redisMqPublisher);
        redisListenerRegister.setRedisTemplate(redisTemplate);
        redisListenerRegister.setRedisMqProperties(redisMqProperties);
        return redisListenerRegister;
    }

    private RedisCacheConfiguration getDefConf(RedisSerializer<String> keySerializer,
                                               RedisSerializer<Object> valueSerializer) {
        return RedisCacheConfiguration.defaultCacheConfig()
                .disableCachingNullValues()
                .computePrefixWith(cacheName -> "semir:".concat(cacheName).concat(":"))
                .serializeKeysWith(RedisSerializationContext.SerializationPair.fromSerializer(keySerializer))
                .serializeValuesWith(RedisSerializationContext.SerializationPair.fromSerializer(valueSerializer));
    }

    private RedisSerializer<String> keySerializer() {
        return new StringRedisSerializer();
    }

    private RedisSerializer<Object> valueSerializer() {
        return new GenericJackson2JsonRedisSerializer();
    }
}
